Как сделать Flash XML слайдшоу на ActionScript 3.0



В этой статье мы покажем вам как сделать Flash XML слайдшоу на ActionScript 3.0. Все изображения и описания, содержащиеся в слайдшоу, будут контролироваться через XML файл, так что вы сможете обновлять и изменять их не трогая исходный FLA файл.

Концепция нашего слайдшоу проста, наш SWF файл будет закачивать XML файл в котором есть текстовые описания к каждому закачиваемому изображению. SWF файл затем закачает все эти изображения за один раз и начнет показ когда все изображения будут усспешно закачаны. В самом SWF файле нет ничего кроме ActionScript так как изображения и описания к ним хранятся во вне этого файла.

Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player



Наша статья разделена на следующие части:

1. Подготовка внешних составляющих и FLA файла.
2. Загрузка и обработка XML файла.
3. Загрузка всх изображений извне.
4. Отображение изображений на экране.
5. Отображение описаний к изображениям на экране.
6. Окончательная доработка кода и добавление простого прелоадера.

 

Подготовка внешних составляющих и FLA файла

start-diagram

Прежде чем начать работать с FLA файлом нам необходимо подготовит все внешние составляющие. Смысл закачивания всего динамически в том, чтобы сделать возможным обновлять наш контент без необходимости изменять исходный FLA файл и снова компелировать SWF каждый раз, когда мы захотим сменить изображения.

Вы можете использовать свои собственные изображения если хотите.

Начнем с создания папки проекта нашего слайдшоу. Внутри этой папки нужно создать папку для изображений и назвать ее images. Рядом с этой папкой будет создан наш XML файл.

XML файл представляет из себя обычный текстовый файл, содержащий в себе специально структуированный код. Откроем Блокнот (или другой простой текстовый редактор, подходящий для программирования, например Notepad++) и сохраним пустой файл как slideshow.xml. Теперь у вас должны быть папка, называющаяся images и xml файл, оба размещенные внутри вашей папки проекта.







Подготавливаем XML файл

foldersМы собираемся наполнить наш XML файл информацией, необходимой для нашего слайдшоу. В нем будет содержаться два вида информации:
1. Нужная для слайдшоу информация, такая как скорость (speed), с которой оно будет работать.
2. Информация об изображениях, такая как URL и image title.

Общая структура нашего XML файла приведена в коде, показанном ниже, Один тэг <slideshow> будет содержать в себе несколько тэгов <image />.

CODE:

<?xml version="1.0" encoding="utf-8"?>
<slideshow para1="value" para2="value" ... >
<image para1="value" ... />
<image para1="value" ... />
<image para1="value" ... />
</slideshow>

Наш код будет содержать следующие параметры, определенные в элементе <slideshow>:

1. Скорость смены изображений в слайдшоу (количество секунд для каждого изображения)

Каждый элемент <image /> будет содержать следующие параметры:

1. image URL
2. image Title

Значения этих параметров будут использованы Flash при помощи .attrbute свойства XML элемента. Значения этих параметров оределены в коде, находящемся ниже, вы можете скопировать и вставить его в ваш XML файл. Вы можете изменить эти параметры в последствии, когда будете конфигурировать свое собственное слайдшоу.

CODE:

<?xml version="1.0" encoding="utf-8"?>
<SLIDESHOW SPEED="2">
<IMAGE URL="images/image1.jpg" TITLE="Snow in Wessex Lane" />
<IMAGE URL="images/image2.jpg" TITLE="Riverside Park" />
<IMAGE URL="images/image3.jpg" TITLE="London Museum" />
<IMAGE URL="images/image4.jpg" TITLE="Castle in Wales" />
</SLIDESHOW>

Вы могли заметить что мы не определили количество изображений в нашем слайдшоу, это потому что ActionScript XML класс может определять количество дочерних нодов внутри элемента и в нашем случае это количество элементов <image /> внутри нашего элемента <slideshow>, тоесть количество изображений в нашем слайдшоу.

Подготовка FLA файла

Теперь, когда внешние составляющие нашего слайдшоу готовы, настало время создать FLA файл. Создайте новый файл во Flash в формате AS3. Сохраните его в той же папке, где находятся ваши XML файл и папка с изображениями. Установите разры вашего FLA файла в 500х500 пикселей и частоту кадров в 30 fps.

properties inspectorДля того чтобы наше слайдшоу работало, мы должны загрузить и обработать наш XML файл, затем поместить все, необходимые нам данные в легко доступные переменные. Загрузка данных потребует использования такого класса как URLLoader Class и обработка XML файла потребует использование класса XML Class.

Создаем необходимые переменные.

Теперь мы должны извлечь данные из нашего XML файла и поместить их для исползования в слайдшоу. Перед тем как попытаться загрузить наши данные нам нужно создать переменные которые будут помещать в себе эти данные. Данные, которые мы будем извлекать из XML это:
1. speed = число, показывающее количество секунд, для показа каждого слайда в слайдшоу.
2. total images = число, показывающее количество изображений в нашем слайдшоу.
3. images = ссылка на список изображений для извлечения URL и title каждого изображения.

Нам необходимо чтобы переменные оставались доступными в течении всего времени работы нашего клипа, так что нам нужно объявить их явно вне любых функций и циклов. Вы можете это сделать написав следующий код в панели Actions (Действия, если у вас русифицированная версия программы):

CODE:

  
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList;
    
    

Мы обновим содержание этих переменных после того как загрузим и оьработаем наш XML файл.

Загружаем XML файл, используя URLLoader Class.

Чтобы закачать любой текстовый контент, такой как XML или HTML во Flash используется класс URLLoader Class. Начнем с создания экземпляра этого класса и затем используем метод .load() чтобы загрузить файл slideshow.xml:

CODE:

  
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
  	var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    
    

Этот код должен загрузить наш XML файл во Flash, но но сам по себе не будет ничего делать, так как Flash все еще не сказано, что делать когда файл загрузится. Чтобы произвести действие, когда файл загружен нам нужно использовать обработчик событий Event.COMPLETE. Мы обработаем это событие при помощи функции processXML(), которую создадим позже. Просто добавте следующий код, чтобы использовать метод .addEventListener() для обработки этого события.

CODE:

  
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList;  
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML);
    
    

Использование слушателя событий позволит нам произвести действие, когда файл полностью загрузится. Действие - это конечно же обработка данных XML.

Обработка данных XML.

Мы собираемся обрабатывать наш XML по средствам функции processXML(), которая запускается когда XML файл заканчивает загружаться. Код, который будет запускаться должен распологаться внутри этой функции. Просто напишите это под кодом, который у нас уже есть:

CODE:

 
  
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
    function processXML (e:Event):void{
    
    }
  
  

Обработка данных нашего XML потребует создания экземпляра класса XML Class и присвоения ему данных нашего XML файла. Сделаем это, распологая код внизу внутри функции processXML():

CODE:

  
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
    function processXML (e:Event):void{
    	var my_xml:XML = new XML(e.target.data); 
    }
    
    

Вы должны запомнить что использование ключевого слова var внутри функции делает эту переменную локальной и временной. Это значит что она будет уничтожена когда функция прекратит выполняться. Мы должны использовать этот способ потому что нам не нужна ссылка на данные XML позже, но мы нуждаемся только в некоторых из их. Это потому что мы создали другие переменные раньше, так что теперь можем использовать их для хранения необходимых данных на протяжении всего клипа.

Теперь мы можем использовать различные методы класса XML Class для извлечения нужных нам данных. Мы будем использовать оператор @ для извлечения нужного нам значения атрибута. Ссылкe на все элементы image мы создадим сохраняя ссылки к нодам image в XML файле, тогда как общее число изображений будет извлекаться, используя метод .length() на XML список изображений (my_images):

CODE:

   
    var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
    function processXML (e:Event):void{
    	var my_xml:XML = new XML(e.target.data); 
   		my_speed=my_xml.@SPEED; 
    	my_images=my_xml.IMAGE; 
    	my_total=my_images.length();
    }
    
  

Теперь, когда данные XML у нас готовы мы будем загружать все наши изображения, используя класс Loader Class. Несколько экземпляров этого класса мы создадим, используя цикл и затем поместим в массив, для легкого доступа в дальнейшем. Мы поместим весь необходимый для этого код в одну функцию, которую назовем loadImages().

Создание функции loadImages()

Для того, чтобы сохранять наш код организованным и легко обновляемым, мы собираемся поместить код, необходимый для данного процесса внутри отдельной функции. Мы собираемся назвать эту функцию loadImages(). Напишите следующий код ниже ранее написанного вами кода:

CODE:

 
  
  function loadImages():void{
  
   }
   
   

Создаем цикл

Нам нужен цикл для нашего слайдшоу, так как нам нужно многократное исполнение одних и тех же команд для каждого изображения. Повторяемый код включает в себя:

1. Получение URL изображения из нашего XML списка изображений.
2. Создание нового экземпляра класса Loader Class чтобы загрузить URL миниатюры.
3. Регистрация загрузчика (loader) слушателем событий (event listener), чтобы показать загруженное изображение.
4. Вставка каждого экземпляра загрузчика (Loader) в массив, чтобы хранить и использовать изображения в последствии.

Начнем с создания цикла. Наш цикл будет работать до тех пор, пока счетчик i не достигнет общего числа наших изображений:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
    
    } 
    } 
    
    

Теперь получим URL изображения и сохраним его в локальной переменной my_url. Эта переменная используется только внутри цикла так что нет нужды в глобальной переменной. Переменная i используется для прохода по элементам XML файла и получения действительных URL, и при помощи оператора @ извлечения значения атрибута:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
   		var my_url:String = my_images[i].@URL;
   } 
    }
    
    

Теперь создадим временный экземпляр класса Loader Class, используя ключевое слово new, и затем загрузим миниатюру изображения используя метод .load(). Это очень просто:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
    	var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url)); 
    } 
    }
    
    

Теперь нам нужно использовать слушатель событий.

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
    	var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url));
    	my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
        onComplete);
    } 
    }
    
    

Добавим теперь каждый экземпляр загрузчика в массив. Нам нужно сделать это чтобы иметь возможность взаимодействовать с каждым экземпляром загрузчика на протяжении слайдшоу. Конечно, перед тем как мы будем добавлять что-то в массив, нам нужно создать сам массив. Вернемся вверх нашего кода и добавим новый массив с названием my_loader_array, мы объявляем этот массив глобально потому что он понадобится нам и далее в проекте, а не только внутри цикла.

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  function processXML (e:Event):void{
  	var my_xml:XML = new XML(e.target.data); 
  	my_speed=my_xml.@SPEED; 
  	my_images=my_xml.IMAGE; 
  	my_total=my_images.length();
  }
    
    

Теперь мы можем вернуться назад к нашему циклу и использовать метод .push() для вставки каждого нового загрузчика в массив:

CODE:

 
  
    function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
    	var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url));
    	my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
        onComplete);
    	my_loaders_array.push(my_loader); 
    } 
    }
    
    

Ну вот. Теперь, когда этот цикл будет вызван, он будет обходить XML файл, извлекать URL, направлять его экземпляру класса Loader Class и затем вставлять этот экземпляр в массив. Конечно, мы еще не определили, что будет происходить, когда каждый экземпляр загрузчика закончит загружать файл. Давайте теперь этим и займемся.

Создание функции слушателя событий (Event Listener) .onComplete

Мы начнем с определения функции слушателя (listener) .onComplete(). Мы уже зарегистрировали эту функцию внутри цикла. Для этого напишите в самом низу нашего с вами кода следущее:

CODE:

 
  
  function onComplete(e:Event):void{
  
  }
  
  

Теперь мы просто попросим слушатель событий обновлять счетчик, чтобы проследить сколько изображений уже успешно закачалось. Нам нужно создать этот счетчик в самом верху нашего кода:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_success_counter:Number = 0;
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  function processXML (e:Event):void{
  	var my_xml:XML = new XML(e.target.data); 
  	my_speed=my_xml.@SPEED; 
  	my_images=my_xml.IMAGE; 
  	my_total=my_images.length();
  }
    
    

Теперь наша функция .onComplete() может просто добавить 1 к значению этого счетчика, используя оператор ++:

CODE:

 
  
  function onComplete(e:Event):void{
 	 my_success_counter++;
  }
  
  

Это означает, что как только каждое изображение зачивается, значение счетчика my_success_counter будет увеличиваться, чтобы показать общее число изображений, которые закончили закачиваться. Для того чтобы начать наше слайдшоу когда все изображения закончат закачиваться, мы должны сравнить это значение с общим числом изображений в слайдшоу, используя сравнение и только затем начать слайдшоу.

CODE:

 
  
  function onComplete(e:Event):void{
  my_success_counter++;
    if (my_success_counter == my_total){
    
  }
  }
  
  

Наше сравнение запустит функцию startShow(), которая начнет наше слайдшоу:

CODE:

 
  
  function onComplete(e:Event):void{
  	my_success_counter++;
    if (my_success_counter == my_total){
    startShow();
    }
  }
  
  

Определим значение этой функции в самом низу нашего кода:

CODE:

 
  
  function startShow():void{
  
  }
  
  

Наша функция loadImages() и поддерживающий её работу слушатель событий теперь готовы. Конечно, для того, чтобы запустить их, мы должны вызвать их из функции processXML(), когда данные XML будут готовы:

CODE:

 
  
  function processXML (e:Event):void{
  	var my_xml:XML = new XML(e.target.data); 
  	my_speed=my_xml.@SPEED; 
  	my_images=my_xml.IMAGE; 
  	my_total=my_images.length();
  	loadImages();
  }
  
  

Создание контейнеров

Первый шаг в отображении наших изображений потребует создания необходимого количества контейнеров, в которых будет помещаться наш контент. Это необходимый шаг для того, чтобы легко управляться с нашим слайдшоу. Нам необходим основной контейнер, внутри которого мы будет отдельный контейнер для изображений и другой для текстовых описаний, который мы добавим позже.

Эти контейнеры должны работать постоянно, поэтому мы должны определить их вне каких либо функций. Напишите в верхней части нашего кода следующее:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList;
  var my_loaders_array:Array = [];
  var my_success_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite(); 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  

Тезерь вернемся к нашей функции startShow(), используем метод addChild() чтобы добавить эти контейнеры в дисплей лист:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
  }
  
  

Наши изображения будут помещены внутрь контейнера my_image_slides. Теперь мы собираемся добавить первое изображение в этот контейнер.

Создание функции nextImage()

Функция nextImage() будет извлекать нужное изображение из массива загрузчиков и показывать его на экране. Для того, чтобы проследить какое конкретно изображение показывается на экране в данный момент, нам нужно создать переменную - счетчик. И опять в верху нашего кода объявим эту переменную. Начальное значение - ноль, обращается к первому изображению в массиве загрузчиков:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_success_counter:Number = 0;
  var my_playback_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite(); 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  

Теперь мы можем создать функцию nextImage(), которая будет использовать счетчик my_playback_counter, чтобы извлекать нужный загрузчик и добавлять его в дисплей лист. Напишите в самом низу нашего с вами кода:

CODE:

 
  
  function nextImage():void{
  	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
  }
  
  

Мы можем вызывать эту функцию из функции startShow(), чтобы первое изображение отображалось, когда слайдшоу начинает работу.

CODE:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
 	nextImage();
  }
  
  

Теперь мы можем первый раз испытать наш клип (Window>Test Movie или Ctrl+Enter), чтобы увидеть первое изображение, отображающиеся на экране.

first slide

Нам нужно, чтобы наша функция nextImage() распологала изображение в центре экрана. Мы можем добиться этого, используя простую формулу, которая использует ширину изображения и ширину экрана, чтобы определить правильное место, чтобы позиционировать изображение в центре. Та же самая концепция примяется и к ветикальной позиции изображения:

CODE:

 
  
  function nextImage():void{
  	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
  } 
  
  

Мы можем сделать чтобы наше изображение постепенно проявлялось, вместо обычного резкого появления, используя класс анимации Tween Class. Естественно, перед тем как использовать этот класс, мы должны импортировать необходимые для этого классы, используя команду import в самом начале нашего кода:

CODE:

 
  
  import fl.transitions.Tween;
  import fl.transitions.easing.*;
  import fl.transitions.TweenEvent;
  
  

Теперь, когда мы сделали это, мы можем использовать простую анимацию, чтобы анимировать значение прозрачности нашего изображения, вот таким образом:

CODE:

 
  
  function nextImage():void{
 	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
    new Tween(my_image,"alpha",Strong.easeOut,0,1,1,true); 
  }
  
  

Теперь вы можете проверить ваш клип отять, чтобы увидеть что первое изображение появляется плавно, используя анимацию.

Этого метода должно быть достаточно для нас, чтобы загрузить любое изображение, нам просто нужно повторять его, используя класс Timer Class.

Используем таймер

Для того, чтобы наше слайдшоу работало, мы должны использовать класс Timer Class, чтобы код исполнялся циклически повторяясь. Наш таймер будет ответственнен за обновление нашего счетчика my_playback_counter и затем вызывал функцию nextImage() чтобы отобразить следующее изображение.

Мы должны иметь возможность использвать наш таймер на протяжении всей работы нашего слайдшоу, поэтому нам нужно объявить его переменную как глобальную в верху нашего с вами кода:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_success_counter:Number = 0;
  var my_playback_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite();
  var my_timer:Timer; 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  

Теперь мы можем сконфигурировать наш таймер из функции startShow().

CODE:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
  	nextImage();
  	my_timer = new Timer(my_speed*1000);
  }
  
  

Наш таймер должен испонять свой код через отдельный слушатель событий, который мы зарегистрируем вместе с ним.

CODE:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
  	nextImage();
 	my_timer = new Timer(my_speed*1000);
    my_timer.addEventListener(TimerEvent.TIMER, timerListener); 
  }
  
  

Ну, и , конечно, мы должны запустить наш таймер, используя метод .start():

CODE:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
 	nextImage();
  	my_timer = new Timer(my_speed*1000);
    my_timer.addEventListener(TimerEvent.TIMER, timerListener); 
    my_timer.start();
  } 
  
  

Наш таймер должен включиться, когда мы будем тестировать клип, но мы еще не написали код, который таймер будет исполнять циклически. Он будет работать в функции timerListener(). Создадим эту функцию в самом низу нашего с вами кода:

CODE:

 
  
  function timerListener (e:TimerEvent):void{
  
  }
  
  

Функция timerListener() будет иметь две основные задачи, первая - увеличивать значение переменной my_playback_counter на 1, так, чтобы слайдшоу двигалось вперед, и затем вызывать функцию nextImage(), чтобы показать следующее изображение:

CODE:

 
  
  function timerListener (e:TimerEvent):void{
  	my_playback_counter++;
    nextImage();
  } 
  
  

Вы можете протестировать ваш клип (Control>Test Movie) и теперь увидеть что слайдшоу работает, показывая изображения с интервалом в 1 секунду. Конечно вы еще можете заметить, что шоу останавливается после показа последней картинки и появляется сообщение об ошибках. Это происходит потому, что значение счетчика показов превышает количество изображений в слайдшоу. Чтобы исправить это положение дел, мы можем использовать условие, чтобы сбрасывать счетчик на ноль, когда он достигнет максимального значения равного количеству изображений в слайдшоу:

CODE:

 
  
  function timerListener (e:TimerEvent):void{
  	my_playback_counter++;
    if (my_playback_counter == my_total)
    my_playback_counter =0;
   } 
    nextImage();
  }
  
  

Ну, вот, теперь все должно работать правильно. Проверьте свой клип, теперь он должен работать циклично. Анимация должна работать плавно, если вы используете изображения одного размера, но если у вас картинки разных размеров, то она может выглядеть не столь хорошо, но с этим мы разберемся позже.

Следующим шагом в нашем проекте будет являться добавление текстовых описаний - лейблов к каждому изображению. Этот процесс очень похож на процесс показа изображений, нам нужно создать множество экземпляров класс TextField Class для каждого лейбла, затем мы должны добавить их в отдельный массив, создать отдельный контейнер, чтобы отображать их, и затем использовать функцию, идентичную nextImage(), чтобы отображать их на экране.

Создание текстовых полей, извлечение лейблов и добавление их в массив.

Мы собираемся создать отдельные текстовые поля для каждого лейбла, присвоить текст этого текстового поля лейблу и затем добавить его в отдельный массив, чтобы иметь возможность свободного доступа к нему. Мы можем сделать это используя нашу уже существующую функцию loadImages() так как эта функция обрабатывает элементы XML, используя цикл.

Начнем с создания нового экземпляра текстового поля под именем my_label:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
  	var my_url:String = my_images[i].@URL;
    var my_loader:Loader = new Loader();
    my_loader.load(new URLRequest(my_url));
    my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
    onComplete);
    my_loaders_array.push(my_loader); 
 	var my_label:TextField = new TextField(); 
 	} 
  }
  
  

Вы можете теперь извлечь лейбл каждого из наших изображений, используя оператор @ извлечь значение атрибута title и прямо установить его как значение для свойства .text текстового поля:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
 		var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url));
    	my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
        onComplete);
    	my_loaders_array.push(my_loader);
	 	var my_label:TextField = new TextField(); 
    	my_label.text = my_images[i].@TITLE;
  	 } 
    }
    
    

Теперь нам нужно так сконфигурировать наше текстовое поле, чтобы оно вмещало лейбл любого размера, используя свойство .autoSize автоматического расширения:

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
  		var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url));
    	my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
        onComplete);
    	my_loaders_array.push(my_loader); 
  		var my_label:TextField = new TextField(); 
    	my_label.text = my_images[i].@TITLE;
    	my_label.autoSize = TextFieldAutoSize.LEFT; 
  	 } 
    } 
    
    

Наш финальный шаг - добавить наше текстовое поле в специальный массив для лейблов. Нам нужен этот массив, чтобы в дальнейшем обращаться к нашим лейблам. Создадим этот массив вверху нашего кода, чтобы он оставался в постоянном доступе:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_labels_array:Array = []; 
  var my_success_counter:Number = 0;
  var my_playback_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite();
  var my_timer:Timer; 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  

Мы можем теперь с легкостью добавить наши лейблы в этот массив, используя метод .push():

CODE:

 
  
  function loadImages():void{
    for (var i:Number = 0; i < my_total; i++){ 
    	var my_url:String = my_images[i].@URL;
    	var my_loader:Loader = new Loader();
    	my_loader.load(new URLRequest(my_url));
    	my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
        onComplete);
    	my_loaders_array.push(my_loader); 
  		var my_label:TextField = new TextField(); 
    	my_label.text = my_images[i].@TITLE;
   	 	my_label.autoSize = TextFieldAutoSize.LEFT; 
    	my_labels_array.push(my_label);
  		} 
    }
    
    

Теперь мы должны создать контейнеры для лейблов.

Создание контейнеров для лейблов

Нам нужен отдельный контейнер для наших лейблов так, чтобы иметь организованную структуру для наших визуальных объектов. У нас есть один для изображений и мы нуждаемся еще в одном для наших текстовых лейблов. Просто объявляем его вверху нашего кода:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_labels_array:Array = []; 
  var my_success_counter:Number = 0;
  var my_playback_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite();
  var my_label_slides:Sprite = new Sprite(); 
  var my_timer:Timer; 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
  
  

Мы можем добавить его в дисплей лист, используя метод .addChild() в нашей функции startShow():

CODE:

 
  
  function startShow():void{
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
    my_slideshow.addChild(my_label_slides);
  	nextImage();
  	my_timer = new Timer(my_speed*1000);
    my_timer.addEventListener(TimerEvent.TIMER, timerListener); 
    my_timer.start();
  }
  
  

Показываем лейблы на экране

Отображение лейблов на экране будет сделано точно таким же способом как и в случае с изображениями.

CODE:

 
  
  function nextImage():void{
  	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
    new Tween(my_image,"alpha",Strong.easeOut,0,1,1,true); 
  	var my_label:TextField = TextField(my_labels_array[my_playback_
    counter]);
    my_labels_slides.addChild(my_label); 
 }
 
 

Теперь наши текстовые поля должны отобразиться на экране, но расположены они не правильно. Их горизонтальная координата должна быть точно такой же как и у изображений, а ветикальная - по нижнему краю изображения. Вычисляется это следующим образом:

CODE:

 
  
  function nextImage():void{
  	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
    new Tween(my_image,"alpha",Strong.easeOut,0,1,1,true); 
  	var my_label:TextField = TextField(my_labels_array[my_playback_
    counter]);
    my_label_slides.addChild(my_label); 
    my_label.x = my_image.x;
    my_label.y = my_image.y + my_image.height; 
  }
  
  

Мы так же можем добавить анимацию прозрачности к текстовым лейблам как мы делали с изображениями, используя Tween Class:

CODE:

 
  
  function nextImage():void{
  	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
    new Tween(my_image,"alpha",Strong.easeOut,0,1,1,true); 
  	var my_label:TextField = TextField(my_labels_array[my_playback_
    counter]);
    my_labels_slides.addChild(my_label); 
    my_label.x = my_image.x;
    my_label.y = my_image.y + my_image.height; 
    new Tween(my_label,"alpha",Strong.easeOut,0,1,1,true); 
  }
  
  

Теперь вы можете протестировать ваш клип и увидеть, что ваши лейблы плавно появляются в правильной позиции. Правда, вы заметите большую проблему с ними, так как предыдущие текстовые поля не убираются, когда появляются новые, напрочь портя всю картину.

slideshow problem

Если вы используете изображения разных размеров, вы так же можете заметить что они остаются фоном, когда другие появляются. Мы решим эту проблему создав новую функцию hidePrev(), чтобы устранить это досадное недоразумение.

Создание функции hidePrev()

Проблема с нашими размножившимися текстовыми лейблами и картинками может быть устранена путем создания функции, прячущей с экрана лейбл и картинку перед тем как показать следующие. Мы должны вызвать эту функцию перед тем как обновим счетчик my_current_playback или даже обратимся к функции nextImage(). Мы хотим убрать первый лейбл и изображение, отображаемое на экране, так что мы можем обратиться к ним, используя их позицию в дисплей листах. Мы можем просто использовать Tween Class, чтобы плавно растворить их, анимируя прозрачность. Вы можете написать следующий код внизу нашего существующего кода, чтобы сделать это:

CODE:

 
  
  function hidePrev():void{
 	var my_image:Loader=Loader(my_image_slides.getChildAt(0)); 
    new Tween(my_image,"alpha",Strong.easeOut,1,0,1,true); 
   	var my_label:TextField=TextField(my_label_slides.getChildAt(0)); 
    new Tween(my_label,"alpha",Strong.easeOut,1,0,1,true); 
  }
  
  

Мы можем теперь вызвать эту функцию прямо из функции слушателя событий нашего таймера:

CODE:

 
  
  function timerListener (e:TimerEvent):void{
  	hidePrev();
  	my_playback_counter++;
    if (my_playback_counter == my_total){
    	my_playback_counter =0;
    } 
  nextImage();
  }
  
  

При тестировании этого кода пропадет только первый слайд, но ничего больше, так происходит потому что все остальные картинки и лейблы расположены после индекса 0 в их дисплей листах до тех пор, пока первые остаются там. Нам нужно убрать изоьражение и лейбл из их дисплей листов после того как они растворятся. Чтобы сделать это нам нужно зарегистрировать одну из наших анимаций со слушателем событий. Нам нужно создать глобальную переменную для нашей анимации в начале нашего кода:

CODE:

 
  
  var my_speed:Number;
  var my_total:Number;
  var my_images:XMLList; 
  var my_loaders_array:Array = [];
  var my_labels_array:Array = []; 
  var my_success_counter:Number = 0;
  var my_playback_counter:Number = 0;
  var my_slideshow:Sprite = new Sprite();
  var my_image_slides:Sprite = new Sprite();
  var my_label_slides:Sprite = new Sprite(); 
  var my_timer:Timer; 
  var my_prev_tween:Tween; 
  var my_xml_loader:URLLoader = new URLLoader();
  my_xml_loader.load(new URLRequest("slideshow.xml"));
  my_xml_loader.addEventListener(Event.COMPLETE, processXML);
   
  

Теперь мы можем добавить слушатель событий к нашей функции hidePrev(). Обе наши анимации картинки и лейбла занимают одинаковое время, так что по этой причине мы можем убрать их обе, используя один и тот же слушатель, вместо отдельного для каждой.

CODE:

 
  
  function hidePrev():void{
  	var my_image:Loader=Loader(my_image_slides.getChildAt(0)); 
    my_prev_tween = new Tween(my_image,"alpha",Strong.easeOut,
    1,0,1,true); 
    my_prev_tween.addEventListener(TweenEvent.MOTION_FINISH, onFadeOut)
  	var my_label:TextField=TextField(my_label_slides.getChildAt(0)); 
    new Tween(my_label,"alpha",Strong.easeOut,1,0,1,true); 
  }
  
  

Теперь мы можем создать функцию onFadeOut() чтобы убрать child с позиции 0 для каждого контейнера:

CODE:

 
  
  function onFadeOut(e:TweenEvent):void{
    my_image_slides.removeChildAt(0);
    my_label_slides.removeChildAt(0);
    }
    
    

Теперь вы можете протестировать ваше слайдшоу, чтобы увидеть что работает оно замечательно.

Добавляем простой прелоадер

В зависимости от количества картинок в вашем слайдшоу, закачивание их может занять продолжительное время. Чтобы информировать пользователей что клип не повис и что он в данный момент успешно закачивается, мы можем добавить простой текст, ообъясняющий это.

Первый шаг в создании этого прелоадера состоит в создании переменной, в которой будет помещаться текстовое поле. Создадим эту переменную в самом верху нашего кода, так как она должна быть глобальной, для возможности постоянного доступа к ней:

CODE:

 
  
  	var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
 	var my_loaders_array:Array = [];
    var my_labels_array:Array = []; 
    var my_success_counter:Number = 0;
    var my_playback_counter:Number = 0;
    var my_slideshow:Sprite = new Sprite();
    var my_image_slides:Sprite = new Sprite();
    var my_label_slides:Sprite = new Sprite(); 
    var my_preloader:TextField;
    var my_timer:Timer; 
    var my_prev_tween:Tween; 
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML);
   
  

Теперь, внутри нашей функции loadImages() мы собираемся создать текстовое поле, чтобы оно показывало слово "Loading", правильно позиционировать его и затем добавить в дисплей лист. Заметьте что код должен быть расположен вне цикла, но внутри тела функции:

CODE:

 
  
function loadImages():void{
  for (var i:Number = 0; i < my_total; i++){ 
 	var my_url:String = my_images[i].@URL;
    var my_loader:Loader = new Loader();
    my_loader.load(new URLRequest(my_url));
    my_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
    onComplete);
    my_loaders_array.push(my_loader); 
    var my_label:TextField = new TextField(); 
    my_label.text = my_images[i].@TITLE;
    my_label.autoSize = TextFieldAutoSize.LEFT; 
    my_labels_array.push(my_label);
  } 
  my_preloader = new TextField();
  my_preloader.text="Loading";
  my_preloader.autoSize = TextFieldAutoSize.CENTER;
  my_preloader.x = (stage.stageWidth - my_preloader.width)/2;
  my_preloader.y = (stage.stageHeight - my_preloader.height)/2;
  addChild(my_preloader);
}

Нам необходимо, чтобы это текстовое поле было убрано из дисплей листа, когда слайдшоу начнет работать:

CODE:

 
  
  function startShow():void{
  	removeChild(my_preloader); 
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
    my_slideshow.addChild(my_label_slides); 
    nextImage();
  	my_timer = new Timer(my_speed*1000);
    my_timer.addEventListener(TimerEvent.TIMER, timerListener); 
    my_timer.start();
  }
  
  

Ну, вот, теперь у нас есть простой текстовый прелоадер, который будет демонстрироваться пока не закачаются все изображения.

Оптимизируем код

Наше слайдшоу должно работать замечательно в большинстве обстоятельств, однако, практика требует от нас оптимизировать код и очистить его от лишнего, чтобы наш клип работал без риска каких либо проблем с памятью. Мы можем сделать это отменяя регистрацию событий и убирая объекты которые больше не нужны. Мы будем делать это шаг за шагом.

Начнем с нашей первой функции слушателя событий processXML(). Раз эта функция уже выполнена, то больше нет необходимости для нее быть зарегистрированной нашим экземпляром URLLoder, а так же нет никакой необходимости в самом экземпляре URLLoader, так как все данные, что нам нужны уже помещены в разных переменных. Мы можем отменить регистрацию события, используя метод removeEventListener() и мы можем убрать экземпляр установив его значение в null:

CODE:

 
  
  function processXML (e:Event):void{
  	var my_xml:XML = new XML(e.target.data); 
    my_speed=my_xml.@SPEED; 
    my_images=my_xml.IMAGE; 
    my_total=my_images.length();
 	loadImages();
  	my_xml_loader.removeEventListener(Event.COMPLETE, processXML); 
    my_xml_loader = null; 
  } 
  
  

Перейдем к процессу загрузки изображений, функция onComplete() тоже больше не нужна, так как все изображения уже закачаны.

CODE:

 
  
  function onComplete(e:Event):void{
  	my_success_counter++;
    if (my_success_counter == my_total){
    	startShow();
  	}
  var my_loaderInfo:LoaderInfo = LoaderInfo(e.target); 
  my_loaderInfo.removeEventListener(Event.COMPLETE, onComplete);

}

Ну и в конце, по причине непредсказуемого процесса очистки от мусора в AS3, анимации класса Tween Class, которые не связаны, используя какую-нибудь постоянную ссылку, могут быть уничтожены в случайном порядке в некоторых браузерах. Чтобы быть уверенными что этого не случится с нашими анимациями, мы можем использовать массив чтобы сохранять ссылки на наши анимации.

Начнем с того, что создадим новый массив вверху нашего кода:

CODE:

 
  
  	var my_speed:Number;
    var my_total:Number;
    var my_images:XMLList; 
    var my_loaders_array:Array = [];
    var my_labels_array:Array = []; 
    var my_success_counter:Number = 0;
    var my_playback_counter:Number = 0;
    var my_slideshow:Sprite = new Sprite();
    var my_image_slides:Sprite = new Sprite();
    var my_label_slides:Sprite = new Sprite(); 
    var my_preloader:TextField;
    var my_timer:Timer; 
    var my_prev_tween:Tween;
    var my_tweens_array:Array = [];
    var my_xml_loader:URLLoader = new URLLoader();
    my_xml_loader.load(new URLRequest("slideshow.xml"));
    my_xml_loader.addEventListener(Event.COMPLETE, processXML); 
    
    

Теперь мы собираемся поместить все наши анимации в этом массиве. Начнем с обновления функции nextImage() вот таким образом:

CODE:

 
  
  function nextImage():void{
   	var my_image:Loader = Loader(my_loaders_array[my_playback_
    counter]);
    my_image_slides.addChild(my_image); 
    my_image.x = (stage.stageWidth - my_image.width)/2;
    my_image.y = (stage.stageHeight - my_image.height)/2; 
    my_tweens_array[0] = new Tween(my_image,"alpha",Strong.easeOut,0,1,
    1,true); 
    var my_label:TextField = TextField(my_labels_array[my_playback_
    counter]);
    my_labels_slides.addChild(my_label); 
    my_label.x = my_image.x;
    my_label.y = my_image.y + my_image.height; 
    my_tweens_array[1] = new Tween(my_label,"alpha",Strong.easeOut,0,1,
    1,true); 
  }
  
  

Ну и финальный шаг - обновим функцию hidePrev() таким же точно образом:

CODE:

 
  
  function hidePrev():void{
  	var my_image:Loader=Loader(my_image_slides.getChildAt(0));
    my_prev_tween = new Tween(my_image,"alpha",Strong.easeOut,1,0,
    1,true); 
    my_prev_tween.addEventListener(TweenEvent.MOTION_FINISH, onFadeOut)
    var my_label:TextField=TextField(my_label_slides.getChildAt(0)); 
    my_tweens_array[2] = new Tween(my_label,"alpha",Strong.easeOut,1,0,
    1,true); 
  }
  
  

Ну и теперь мы можем также убрать текстовое поле прелоадеракогда шоу начнется, вместо того , чтобы просто убрать его из дисплей листа. Мы можем сделать это, установив значение этой переменно на null:

CODE:

 
  
  function startShow():void{
  	removeChild(my_preloader); 
    my_preloader = null;
  	addChild(my_slideshow);
    my_slideshow.addChild(my_image_slides);
    my_slideshow.addChild(my_label_slides); 
  	nextImage();
 	my_timer = new Timer(my_speed*1000);
    my_timer.addEventListener(TimerEvent.TIMER, timerListener); 
    my_timer.start();
  } 
  
  

Ну, вот, теперь у нас сполностью функциональное и оптимизированное слайдшоу.



Перевод с английского языка: Солнцев А.

Оригинал статьи на английском языке:   www.republicofcode.com





Комментарии ВКонтакте

arrow вернуться к странице статей про Flash